package com.example.generator.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.example.generator.constant.AppConstant;
import com.example.generator.entity.TableColumnDO;
import com.example.generator.entity.TableInfoDO;
import com.example.generator.entity.TableInfoPageDTO;
import com.example.generator.entity.enums.ColumnTypeEnum;
import com.example.generator.repository.ITableColumnDomainRepository;
import com.example.generator.repository.ITableInfoDomainRepository;
import com.example.generator.service.BaseService;
import com.example.generator.utils.ConvertColumnClassUtils;
import com.example.generator.utils.ConvertTableClassUtils;
import lombok.AllArgsConstructor;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.File;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * com.example.generator.service.impl
 *
 * @author smallNorth_Lee
 * @date 2022/1/14
 */
@Service
@AllArgsConstructor
public class GenerationJavaClassImpl extends BaseService {

    private final ITableColumnDomainRepository tableColumnDomainService;

    private final ITableInfoDomainRepository tableInfoDomainService;

    private static final Configuration CONFIG = getConfig();

    /**
     * @param objectMap       项目配置信息
     * @param projectRootPath 项目文件路径
     * @param tableNames       表名
     */
    public void doGeneration(Map<String, Object> objectMap, String projectRootPath, String tableNames) {
//        tableNames += "sys_user";
        //生成该库下所有表的代码
        if (StringUtils.isEmpty(tableNames)) {
            TableInfoPageDTO tableInfoPageDTO = new TableInfoPageDTO();
            tableInfoPageDTO.setSize(1000);
            tableInfoPageDTO.setCurrent(1);
            IPage<TableInfoDO> tableInfoDOIPage = tableInfoDomainService.queryTables(tableInfoPageDTO);
            List<TableInfoDO> records = tableInfoDOIPage.getRecords();
            records.forEach(tableInfoDO -> {
                String className = ConvertTableClassUtils.getClassName(tableInfoDO.getTableName());
                createCode(projectRootPath, className, convertDataModel(objectMap, tableInfoDO.getTableName(), className));
            });
        } else {
            String[] splitTableName = tableNames.split(",");
            for (String name : splitTableName) {
                String className = ConvertTableClassUtils.getClassName(name);
                createCode(projectRootPath, className, convertDataModel(objectMap, name, className));
            }
        }
    }

    /**
     * 封装dataModel
     *
     * @param tableName 表名
     */
    private Map<String, Object> convertDataModel(Map<String, Object> objectMap, String tableName, String className) {
        List<TableColumnDO> tableColumns = tableColumnDomainService.queryTableColumn(tableName);
        //公共字段不生成,如需要手动添加
        List<TableColumnDO> resTableColumn = new ArrayList<>();
        AtomicBoolean hasBigDecimal = new AtomicBoolean(false);
        AtomicBoolean hasLocalDate = new AtomicBoolean(false);
        AtomicBoolean hasLocalDateTime = new AtomicBoolean(false);
        tableColumns.forEach(tableColumnDO -> {
            if (!AppConstant.COMMON_FIELD.contains(tableColumnDO.getColumnName())) {
                String columnType = CONFIG.getString(tableColumnDO.getDataType());
                if (!hasBigDecimal.get() && ColumnTypeEnum.BIG_DECIMAL.getColumnType().equals(columnType)) {
                    hasBigDecimal.set(true);
                }
                if (!hasLocalDate.get() && ColumnTypeEnum.LOCAL_DATE.getColumnType().equals(columnType)) {
                    hasLocalDate.set(true);
                }
                if (!hasLocalDateTime.get() && ColumnTypeEnum.LOCAL_DATE_TIME.getColumnType().equals(columnType)) {
                    hasLocalDateTime.set(true);
                }
                tableColumnDO.setDataType(CONFIG.getString(tableColumnDO.getDataType()));
                tableColumnDO.setColumnName(ConvertColumnClassUtils.getColumnName(tableColumnDO.getColumnName()));
                resTableColumn.add(tableColumnDO);
            }
        });
        objectMap.put("className", className);
        TableInfoDO tableInfoDO = tableInfoDomainService.queryTableInfo(tableName);
        objectMap.put("comments", tableInfoDO.getTableComment());
        objectMap.put("columns", resTableColumn);
        objectMap.put("tableName", tableName);
        //转小写别名
        String tableAliasName = className.substring(0, 1).toLowerCase() + className.substring(1);
        objectMap.put("tableAliasName", tableAliasName);
        objectMap.put("apiName", tableName.replace("_", "/"));
        objectMap.put("baseEntity", objectMap.get("packageName") + ".utils.mp");
        objectMap.put("hasBigDecimal", hasBigDecimal.get());
        objectMap.put("hasLocalDate", hasLocalDate.get());
        objectMap.put("hasLocalDateTime", hasLocalDateTime.get());
        return objectMap;
    }

    /**
     * 生成代码
     *
     * @param projectRootPath 绝对路径
     * @param className       类名
     * @param objectMap       数据
     */
    private void createCode(String projectRootPath, String className, Map<String, Object> objectMap) {
        super.writeFile(new File(projectRootPath + "/entity", className + "DTO.java"), "Entity.java.ftl", objectMap);
        super.writeFile(new File(projectRootPath + "/entity", className + "Query.java"), "QueryDTO.java.ftl", objectMap);
        super.writeFile(new File(projectRootPath + "/vo", className + "VO.java"), "VO.java.ftl", objectMap);
        super.writeFile(new File(projectRootPath + "/service", "I" + className + "Service.java"), "Service.java.ftl", objectMap);
        super.writeFile(new File(projectRootPath + "/service/impl", className + "ServiceImpl.java"), "ServiceImpl.java.ftl", objectMap);
        super.writeFile(new File(projectRootPath + "/controller", className + "Controller.java"), "Controller.java.ftl", objectMap);
        super.writeFile(new File(projectRootPath + "/application", className + "AppService.java"), "appService.java.ftl", objectMap);
        super.writeFile(new File(projectRootPath + "/mapper", className + "Mapper.java"), "Mapper.java.ftl", objectMap);
        super.writeFile(new File(projectRootPath + "/mapper/xml", className + "Mapper.xml"), "Mapper.xml.ftl", objectMap);
        super.writeFile(new File(projectRootPath + "/enums", "TemplateEnum.java"), "TemplateEnum.java.ftl", objectMap);
        List<TableColumnDO> resTableColumn = (List<TableColumnDO>) objectMap.get("columns");
        objectMap.remove("columns");
        resTableColumn.removeIf(x -> "id".equals(x.getColumnName()));
        objectMap.put("columns",resTableColumn);
        super.writeFile(new File(projectRootPath + "/po", className + ".java"), "PO.java.ftl", objectMap);

    }

    /**
     * 获取配置信息
     *
     * @return
     */
    public static Configuration getConfig() {
        try {
            return new PropertiesConfiguration("generator.properties");
        } catch (ConfigurationException e) {
            throw new RuntimeException("获取配置文件失败，", e);
        }
    }


}
